package com.hnsp.edge;

import com.alibaba.fastjson.JSONObject;
import edge.DeviceGrpc;
import edge.EdgeMessage;
import edge.UploadServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
import io.grpc.ServerBuilder;

/**
 * 边设备app节点grpc客户端工具.
 * @author Zhangjialei
 * @date 2023/6/9 11:03
 */
public class EdgeGrpc {

    /**
     * appid
     */
    private String appId = null;
    /**
     * 设备sn, 请在web端创建设备
     */
    private String sn = null;

    /**
     * 协议版本
     */
    private String version = null;

    /**
     * 边缘端ip
     */
    private String targetHost = null;

    /**
     * 边缘端端口号
     */
    private int targetPort = 8083;

    /**
     * 本地appip
     */
    private String localHost = null;

    /**
     * 本地端口号
     */
    private int localPort = 8082;

    /**
     * 创建客户端连接
     */
    ManagedChannel client = null;
    /**
     * 存根
     */
    UploadServiceGrpc.UploadServiceBlockingStub blockingStub = null;
    /**
     * 设备注册服务
     */
    EdgeMessage.RequestData.Builder registerBuilder = EdgeMessage.RequestData.newBuilder();

    /**
     * 状态上传服务
     */
    EdgeMessage.RequestData.Builder statusBuilder = EdgeMessage.RequestData.newBuilder();
    /**
     * 属性上报服务.
     */
    EdgeMessage.RequestData.Builder propertyBuilder = EdgeMessage.RequestData.newBuilder();
    /**
     * 事件上报服务
     */

    EdgeMessage.RequestData.Builder eventBuilder = EdgeMessage.RequestData.newBuilder();

    /**
     * 初始化连接
     */
    public void init() {
        // 创建客户端连接
        client = ManagedChannelBuilder.forAddress(targetHost, targetPort).usePlaintext(true).build();
        // 创建存根
        blockingStub = UploadServiceGrpc.newBlockingStub(client);
    }

    /**
     * 设备注册.
     */
    public void registerDevice() {
        registerBuilder.setAppId(appId);
        registerBuilder.setSn(sn);
        // TODO Type 需要设置成枚举
        registerBuilder.setType("5.1");
        registerBuilder.setV(version);
        registerBuilder.setTime((int) System.currentTimeMillis());
        String payload = String.format("{\"address\":\"%s:%d\"}", localHost, localPort);
        registerBuilder.setPayload(payload);
        EdgeMessage.Result registerResult = blockingStub.registerDevice(registerBuilder.build());
        System.out.println(JSONObject.toJSONString(registerResult));
    }


    /**
     * 上报状态.
     *
     * @param state TODO 状态标识 需要设置成枚举
     */
    public void uploadStatus(String state) {
        statusBuilder.setAppId(appId);
        statusBuilder.setSn(sn);
        // TODO Type 需要设置成枚举
        statusBuilder.setType("0");
        statusBuilder.setS(state);
        statusBuilder.setTime((int) System.currentTimeMillis());
        EdgeMessage.Result statusResult = blockingStub.uploadStatus(statusBuilder.build());
        System.out.println(JSONObject.toJSONString(statusResult));
    }

    /**
     * 上报属性.
     * @param payload 属性负载数据
     */
    public void uploadProperty(String payload) {
        propertyBuilder.setAppId(appId);
        propertyBuilder.setSn(sn);
        // TODO Type 需要设置成枚举
        propertyBuilder.setType("1");
        propertyBuilder.setTime((int) System.currentTimeMillis());
        propertyBuilder.setPayload(payload);
        EdgeMessage.Result propertyResult = blockingStub.uploadProperty(propertyBuilder.build());
        System.out.println(JSONObject.toJSONString(propertyResult));
    }

    /**
     * 上传事件
     * @param payload 事件负载数据
     */
    public void uploadEvent(String payload) {
        eventBuilder.setAppId(appId);
        eventBuilder.setSn(sn);
        // TODO Type 需要设置成枚举
        eventBuilder.setType("2");
        eventBuilder.setTime((int) System.currentTimeMillis());
        eventBuilder.setPayload(payload);
        EdgeMessage.Result eventResult = blockingStub.uploadEvent(eventBuilder.build());
        System.out.println(JSONObject.toJSONString(eventResult));
    }

    /**
     * 启动本地监听服务.
     * 在后台启动一个监听线程, 用于监听接收边端下发的数据.
     * @param grpcServerImpl grpc监听服务实现.
     */
    public void startLocalService(DeviceGrpc.DeviceImplBase grpcServerImpl) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //启动app监听服务
                Server server = null;
                try {
                    server = ServerBuilder.forPort(localPort)
                            .addService(grpcServerImpl)
                            .build().start();
                    //阻塞防止退出
                    if (server != null) {
                        server.awaitTermination();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            }
        }).start();
    }

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getSn() {
        return sn;
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String v) {
        this.version = v;
    }

    public String getTargetHost() {
        return targetHost;
    }

    public void setTargetHost(String targetHost) {
        this.targetHost = targetHost;
    }

    public int getTargetPort() {
        return targetPort;
    }

    public void setTargetPort(int targetPort) {
        this.targetPort = targetPort;
    }

    public String getLocalHost() {
        return localHost;
    }

    public void setLocalHost(String localHost) {
        this.localHost = localHost;
    }

    public int getLocalPort() {
        return localPort;
    }

    public void setLocalPort(int localPort) {
        this.localPort = localPort;
    }
}
